using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace FireStarter.CodeGeneration
{
    internal abstract class CodeDomBase
    {
        protected CodeDomProvider _codeDomProvider;

        public CodeDomBase(CodeDomProvider codeDomProvider)
        {
            _codeDomProvider = codeDomProvider;
        }

        protected abstract CodeCompileUnit GetCodeCompileUnit();

        public String GenerateCode(string fileName, CodeGeneratorOptions codeGeneratorOptions, bool abortIfExists, bool removeAutoComment)
        {

            // Build the output file name.
            String sourceFile;
            if (_codeDomProvider.FileExtension[0] == '.')
            {
                sourceFile = fileName + _codeDomProvider.FileExtension;
            }
            else
            {
                sourceFile = fileName + "." + _codeDomProvider.FileExtension;
            }

            if (abortIfExists && File.Exists(sourceFile))
            {
                return sourceFile;
            }

            StringWriter stringWriter = new StringWriter();
            // Create a TextWriter to a StreamWriter to the output string.
            IndentedTextWriter textWriter = new IndentedTextWriter(stringWriter, "    ");

            // Generate source code using the code provider.
            CodeCompileUnit codeCompileUnit = GetCodeCompileUnit();
            _codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, textWriter, codeGeneratorOptions);

            string fileContents = stringWriter.ToString();

            // Close the output string.
            textWriter.Close();

            if (removeAutoComment)
            {
                fileContents = RemoveAutoComment(fileContents);
            }
            fileContents = RemoveEmptyComments(fileContents);

            File.WriteAllText(sourceFile, fileContents);

            //// Create a TextWriter to a StreamWriter to the output file.
            //IndentedTextWriter textWriter = new IndentedTextWriter(
            //        new StreamWriter(sourceFile, false), "    ");

            //// Generate source code using the code provider.
            //_codeDomProvider.GenerateCodeFromCompileUnit(compileunit, textWriter,
            //        codeGeneratorOptions);

            //// Close the output file.
            //textWriter.Close();

            return sourceFile;
        }

        protected static string BuildFileComment(string comment)
        {
            string standardComment = "This class was auto-generated " +
                                     "for use with the Habanero Enterprise Framework.";
            if (comment.Length > 0)
            {
                comment = standardComment + Environment.NewLine + comment;
            }
            else
            {
                comment = standardComment;
            }
            comment = "-------------------------------------------------------" +
                      "-----------------------" + Environment.NewLine + " " + comment;
            comment += Environment.NewLine + " ------------------------" +
                       "------------------------------------------------------";
            return comment;
        }

        protected static void EnsureAssemblyImported(CodeNamespace classNamespace, string assemblyName)
        {
            if (assemblyName.Length > 0)
            {
                bool found = HasNamespaceImport(classNamespace, assemblyName);
                if (!found)
                {
                    classNamespace.Imports.Add(new CodeNamespaceImport(assemblyName));
                }
            }
        }

        protected static bool HasNamespaceImport(CodeNamespace classNamespace, string assembly)
        {
            bool found = false;
            if (classNamespace.Name == assembly) return true;
            foreach (CodeNamespaceImport import in classNamespace.Imports)
            {
                if (import.Namespace == assembly)
                {
                    found = true;
                    break;
                }
            }
            return found;
        }

        protected static void CreateRegion(CodeTypeMember firstMember, CodeTypeMember lastMember, string regionName)
        {
            if (firstMember != null)
            {
                firstMember.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, regionName));
                lastMember.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, ""));
            }
        }

        private static string RemoveAutoComment(string fileContents)
        {
            string autoCommentStart = @"//------------------------------------------------------------------------------";
            autoCommentStart += Environment.NewLine + @"// <auto-generated>";
            if (fileContents.StartsWith(autoCommentStart))
            {
                string autoCommentEnd = @"// </auto-generated>" + Environment.NewLine;
                autoCommentEnd += @"//------------------------------------------------------------------------------";
                autoCommentEnd += Environment.NewLine;
                int pos = fileContents.IndexOf(autoCommentEnd);
                if (pos > 0)
                {
                    pos += autoCommentEnd.Length;
                    fileContents = fileContents.Remove(0, pos);
                }
            }
            return fileContents;
        }

        private static string RemoveEmptyComments(string fileContents)
        {
            fileContents = fileContents.Replace(Environment.NewLine + @"// " + Environment.NewLine,
                                                Environment.NewLine + Environment.NewLine);
            return fileContents;
        }
    }
}